﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using NHibernate;
using NHibernate.Criterion;
using Studentium.Entities;
using Studentium.Util;

namespace Studentium.UIElements
{
    public partial class StudentsControl : UserControl
    {
        private MainForm mainController;
        private StudentInfoTabs infoTabs;
        private bool studentMode;

        private const string ALL = "All";
        private const string ACTIVE = "Active";
        private const string PASSIVE = "2 weeks inactive";
        private const string FINISHED = "Finished";

        public bool StudentMode
        {
            get { return studentMode; }
        }

        public MainForm MainController
        {
            get { return mainController; }
            set { mainController = value; }
        }        

        public StudentsControl() : this(true)
        {            
        }

        public StudentsControl(bool studentMode)
        {            
            InitializeComponent();

            activityCombo.DataSource = new []{ALL, ACTIVE, PASSIVE, FINISHED};

            this.studentMode = studentMode;
            contentPages.ItemSize = new Size(0,1);

            fromDatePicker.Value = new DateTime(2010,1,1);            
            fromDatePicker.Format = DateTimePickerFormat.Custom;
            fromDatePicker.CustomFormat = "dd MMMM yyyy";

            toDatePicker.Value = DateTime.Now.AddYears(2);
            toDatePicker.Format = DateTimePickerFormat.Custom;
            toDatePicker.CustomFormat = "dd MMMM yyyy";

            if (!studentMode)
            {
                idNameSearchLbl.Text = "Human name/surname:";
                addStudentBtn.Text = "Add human";
                levelBox.Visible = false;
                activityCombo.Visible = false;
                fromDatePicker.Visible = false;                
                toDatePicker.Visible = false;                
                searchStudentBtn.Location = new Point(250,3);
                separatorLbl.Location = new Point(330, 9);
                addStudentBtn.Location = new Point(345, 3);                
            }

            levelBox.DataSource = Enum.GetValues(typeof (StudentLevel));            

            //Schedule.Initialize();
        }

        private void searchStudentBtn_Click(object sender, EventArgs e)
        {
            var query = studentIdBox.Text.Trim().Split(' ')[0];
            var level = (StudentLevel) levelBox.SelectedItem;

            SearchStudent(query, level);
        }

        private void SearchStudent(string query, StudentLevel level)
        {
            ICriterion businessIdCriterion = studentMode
                                                 ? Expression.Not(Expression.Eq("BusinessId", 0))
                                                 : Expression.Eq("BusinessId", 0);

            ICriterion nameExpression = Expression.Or(Expression.Like("LastName", query, MatchMode.Anywhere),
                                                      Expression.Like("FirstName", query, MatchMode.Anywhere));

            ICriterion filterExpression = Expression.Or(nameExpression,
                                                        Expression.Eq("Phone", query));


            int number;
            if (studentMode && Int32.TryParse(query, out number))
            {
                filterExpression = Expression.Or(filterExpression,
                                                 Expression.Eq("BusinessId", number));
            }

            if (level != StudentLevel.Unknown)
                filterExpression = Expression.And(filterExpression,
                                                  Expression.Like("Level", level));


            // separate finished and unfinished students
            if(activityCombo.SelectedItem.ToString() == FINISHED)
            {
                filterExpression = Expression.And(filterExpression, Expression.Eq("Finished", true));
            }
            // for ALL filter - finished status isn't used
            else if (activityCombo.SelectedItem.ToString() != ALL)
            {
                filterExpression = Expression.And(filterExpression, Expression.Eq("Finished", false));
            }

            using (ISession session = mainController.GetSession())
            {
                IList<Student> students = session.CreateCriteria(typeof (Student)).
                    Add(filterExpression).
                    Add(businessIdCriterion).
                    List<Student>();

                // filter result basing on activity
                if (activityCombo.SelectedItem.ToString() == ACTIVE ||
                    activityCombo.SelectedItem.ToString() == PASSIVE)
                {
                    var activityDateFrom = new DateTime(1900);
                    var activityDateTo = DateTime.Now.AddYears(1);
                    switch (activityCombo.SelectedItem.ToString())
                    {
                        case ACTIVE:
                            activityDateTo = DateTime.Now.AddYears(1);
                            activityDateFrom = DateTime.Now.AddDays(-2 * 7);
                            break;
                        case PASSIVE:
                            activityDateTo = DateTime.Now.AddDays(-2 * 7);
                            activityDateFrom = DateTime.Now.AddDays(-6 * 7);
                            break;
                    }

                    // filter active/passive/finished
                    students = students.Where( student =>
                    {
                        DateTime maxTime = DateTime.MinValue;
                        if (student.Classes.Count != 0)
                        {
                            var lastClassDate = new DateTime(student.Classes.Max(attendance => attendance.Date.Ticks));
                            maxTime = lastClassDate > maxTime ? lastClassDate : maxTime;                            
                        }
                        else
                        {
                            maxTime = student.RegistrationDate;
                        }

                        if (maxTime == DateTime.MinValue)
                            return false;

                        return maxTime > activityDateFrom && maxTime <= activityDateTo;
                    }).ToList();
                }

                DateTime toDate = new DateTime(toDatePicker.Value.Year, 
                                               toDatePicker.Value.Month,
                                               toDatePicker.Value.Day).AddDays(1).AddMinutes(-1);

                DateTime fromDate = new DateTime(fromDatePicker.Value.Year,
                                                 fromDatePicker.Value.Month,
                                                 fromDatePicker.Value.Day);

                // filter by payment finish date
                students = students.Where(student =>
                                student.LastActivityDate <= toDate &&
                                student.LastActivityDate >= fromDate
                              ).ToList();

                if (students.Count == 1)
                {
                    ShowStudent(students[0]);
                }
                else
                {
                    ShowStudents(students);
                }
            }
        }

        private void addStudentBtn_Click(object sender, EventArgs e)
        {
            // create new student
            var currentStudent = new Student {RegistrationDate = DateTime.Now};

            if (studentMode)
                currentStudent.BusinessId = GetMaxStudentBusinessId() + 1;
            else
                currentStudent.BusinessId = 0;

            try
            {
                using (ISession session = mainController.GetSession())
                using (ITransaction transaction = session.BeginTransaction())
                {
                    session.Save(currentStudent);
                    transaction.Commit();
                }
            }
            catch (Exception ex)
            {
                Log.log("Error during student creation", ex);
                MessageBox.Show(
                    "Student cann't be created now - try restart application or contact application developer", "Error",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Error);
            }

            ShowStudent(currentStudent);
        }

        private void searchResultsGrid_DoubleClick(object sender, EventArgs e)
        {
            Student student = (Student)searchResultsGrid.CurrentRow.DataBoundItem;
            ShowStudent(student);
        }

        private void ShowStudents(IList<Student> students)
        {
            BindingSource source = new BindingSource();
            source.DataSource = new BindingList<Student>(students);
            searchResultsGrid.DataSource = source;
            contentPages.SelectedIndex = 0;
            infoLbl.Text = "Found: " + students.Count + " student(s)";
            if (students.Count == 0)
                MessageBox.Show("No one was found", "Empty list", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }


        public void ShowStudent(Student student)
        {
            infoLbl.Text = "";
            // if infoTabs doesn't exist - create them
            if (infoTabs == null)
            {
                infoTabs = new StudentInfoTabs(student, this);
                infoTabs.Location = new Point(5, 5);
                infoTabs.Anchor = AnchorStyles.Bottom | AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;
                contentPages.TabPages[1].Controls.Add(infoTabs);
                if (!studentMode)
                    infoTabs.RemoveClassesAndPaymentTabs();
            }
            // otherwise use existing
            else                            
                infoTabs.ShowStudentInfos(student);            

            contentPages.SelectedIndex = 1;
        }


        public int GetMaxStudentBusinessId()
        {
            using (ISession session = mainController.GetSession())
            {
                IList<Student> list =
                    session.CreateCriteria(typeof (Student)).AddOrder(Order.Desc("BusinessId")).List<Student>();
                if (list.Count == 0)
                {
                    return 0;
                }
                return list[0].BusinessId;
            }
        }

        // this is called from calendar tab when calendar entry is removed
        internal void ReloadStudentView()
        {
            if (infoTabs == null)
                return;
            
            // reload student
            SearchStudent(infoTabs.CurrentStudent.BusinessId.ToString(), StudentLevel.Unknown);
        }

        private void studentIdBox_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == (char)Keys.Return)
            {
                searchStudentBtn_Click(null, null);
            }
        }
    }
}
